//////////////////////////////////////////////////////////////////////////////////////////////
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//	File			:	"Game.cpp"
//	Authors			:	Jake Castillo,
//	Project			:	Project Aetheryte
//	Date Modified	:	8/6/2013
//	Purpose			:	Runs the functionality of the game.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//////////////////////////////////////////////////////////////////////////////////////////////


#include "Game.h"
#include <tchar.h>
#include <cstring>
#include <cassert>

// Insert Class list here
#include "../SGD Wrappers/CSGD_Direct3D.h"
#include "../SGD Wrappers/CSGD_DirectInput.h"
#include "../SGD Wrappers/CSGD_TextureManager.h"
#include "../SGD Wrappers/CSGD_XAudio2.h"
#include "../SGD Wrappers/CSGD_MessageSystem.h"

#include "../Game States/IGameState.h"
#include "../Game States/MainMenuState.h"

#include "../Fonts/Font.h"
#include "../Fonts/TitleFont.h"
#include "../Fonts/MenuFont.h"

//***********************************************************
// SINGLETON
//	- instantiate the static data member
/*static*/ CGame* CGame::s_pInstance = nullptr;

// GetInstance
//	- allocates the singleton object ONCE
//	- returns the singleton object
/*static*/ CGame* CGame::GetInstance( void )
{
	if( s_pInstance == nullptr )
		s_pInstance = new CGame;

	return s_pInstance;
}

// DeleteInstance
//	- deallocates the singleton object
/*static*/ void	  CGame::DeleteInstance( void )
{
	delete s_pInstance;
	s_pInstance = nullptr;
}


//***********************************************************
// CONSTRUCTOR
//	- set ALL the data members to 'clean' values
CGame::CGame( void )
{
	// Seed the random number generator
	srand( (unsigned int)GetTickCount() );
	rand();

	m_nScreenWidth		= 1;
	m_nScreenHeight		= 1;
	m_bIsWindowed		= true;

	m_dwCurrTime		= 0;

	m_pD3D				= nullptr;
	m_pDI				= nullptr;
	m_pTM				= nullptr;
	m_pXA				= nullptr;

	m_pCurrState		= nullptr;


	language			= English;

	Paused = false;
	Loaded = false;

	loadID = -1;

	m_pCurrState = nullptr;

	hideCursor = true;
}

//***********************************************************
// DESTRUCTOR
CGame::~CGame(void)
{
}


//***********************************************************
// INITIALIZE
//	- setup all the data members
void CGame::Initialize( HWND hWnd, HINSTANCE hInstance,
					   int nWidth, int nHeight,
					   bool bWindowed )
{
	ShowCursor(!hideCursor);

	// Catch the Window Info
	pHWND		= hWnd;
	pInstance	= hInstance;

	// Store the Wrapper singletons
	m_pD3D			= CSGD_Direct3D::GetInstance();
	m_pDI			= CSGD_DirectInput::GetInstance();
	m_pTM			= CSGD_TextureManager::GetInstance();
	m_pXA			= CSGD_XAudio2::GetInstance();
	//m_pAS           = AnimationSystem::GetInstance();

	// Store the parameters
	m_nScreenWidth	= nWidth;
	m_nScreenHeight	= nHeight;
	res.width		= nWidth;
	res.height		= nHeight;
	m_bIsWindowed	= bWindowed;

	//StartWrappers( hWnd, hInstance, m_nScreenWidth, m_nScreenHeight, m_bIsWindowed );

	//// Initialize the Wrappers
	m_pD3D->Initialize( hWnd, m_nScreenWidth, m_nScreenHeight, m_bIsWindowed, true );
	m_pDI->Initialize( hWnd, hInstance, DI_KEYBOARD | DI_JOYSTICKS );
	m_pTM->Initialize( m_pD3D->GetDirect3DDevice(), m_pD3D->GetSprite() );
	m_pXA->Initialize();
	//m_pAS->Initialize();

	/*Font* font1 = new MenuFont;
	font1->Initialize( _T("Resource/Images/Fonts/MenuFont.png"), 42, 42, 12, 8, false, _T(' '), CGame::GetInstance()->English );

	Font* font2 = new MenuFont;
	font2->Initialize( _T("Resource/Images/Fonts/EorzeanFont.png"), 42, 42, 12, 8, false, _T(' '), CGame::GetInstance()->Eorzean );

	Font* font3 = new MenuFont;
	font3->Initialize( _T("Resource/Images/Fonts/OldEnglish.png"), 42, 42, 12, 19, false, _T(' '), CGame::GetInstance()->Swedish );

	vFonts.push_back( font1 );
	vFonts.push_back( font2 );
	vFonts.push_back( font3 );*/

	//vFonts.reserve(3);

	//for(unsigned int i = 0; i < 3; i++)
	//	vFonts[i] = nullptr;

	//loadID = m_pTM->LoadTexture(_T("Resource/Images/Menu BG/Loading Screen animation/loading_screen.png"));

	CreateFonts();

	// Store the current time
	m_dwCurrTime = GetTickCount();

	Paused = false;

	// Activate the State Machine
	ChangeState( MainMenuState::GetInstance() );
	m_pPrevState = m_pCurrState;
}

//***********************************************************
// Main
//	- run one frame of the game
bool CGame::Main( void )
{
	if( Input() == false )
		return false;

	if(!Paused)
		Update();
	Render();
	return true;
}

//***********************************************************
// Terminate
//	- clean up memory
//	- shutdown the SGD Wrappers
void CGame::Terminate( void )
{
	if(m_pCurrState != nullptr)
		m_pCurrState->Exit();

	//for(unsigned int i = 0; i < vFonts.size(); i++)
	//{
	//	vFonts[i]->Terminate();
	//	delete vFonts[i];
	//	vFonts[i] = nullptr;
	//}

	//vFonts.clear();

	Title->Terminate();
	delete Title;

	Menu->Terminate();
	delete Menu;

	// Shutdown the wrappers in REVERSE ORDER!
	m_pXA->Terminate();
	m_pTM->Terminate();
	m_pDI->Terminate();
	m_pD3D->Terminate();
	//m_pAS->Uninitialize();

	//ParticleSystem::GetInstance()->RemoveAll();
	//ParticleSystem::GetInstance()->UnloadEmitters();
	//ParticleSystem::DeleteInstance();

	//EntityManager::GetInstance()->RemoveAll();
	//EntityManager::DeleteInstance();

	//WorldSystem::GetInstance()->Terminate();
	//WorldSystem::DeleteInstance();

	//m_pAS->DeleteInstance();
	CSGD_MessageSystem::GetInstance()->ShutdownMessageSystem();

	// Reset ALL the data members
	m_pD3D			= nullptr;
	m_pDI			= nullptr;
	m_pTM			= nullptr;
	m_pXA			= nullptr;	

	//EntityManager::DeleteInstance();

	m_nScreenWidth	= 1;
	m_nScreenHeight	= 1;
	m_bIsWindowed	= true;
}

//***********************************************************
// Input
//	- handle the user's input
bool CGame::Input( void )
{
	// Read the devices
	m_pDI->ReadDevices();

	if( m_pDI->KeyPressed( DIK_RETURN ) == true && m_pDI->KeyDown( DIK_LALT ) ||
		m_pDI->KeyPressed( DIK_RETURN ) == true && m_pDI->KeyDown( DIK_RALT ) )
	{
		SetWindowed(!m_bIsWindowed);

		m_pDI->ClearInput();
	}

	if( m_pDI->KeyPressed( DIK_F7 ) )
	{
		HideCursor(!hideCursor);
		m_pDI->ClearInput();
	}

	if(m_pCurrState != nullptr)
		if( m_pCurrState->Input() == false )
			return false;

	return true;
}

//***********************************************************
// Update
//	- update the game objects
void CGame::Update( void )
{
	// Update the audio
	m_pXA->Update();

	// Calculate the elapsed time between frames
	DWORD dwNow = GetTickCount();

	float fElapsedTime = (dwNow - m_dwCurrTime) / 1000.0f;

	// Cap the elapsed time to 1/8th of a second
	if( fElapsedTime > 0.125f )
		fElapsedTime = 0.125f;

	// Store the current time
	m_dwCurrTime = dwNow;

	if(m_pCurrState != nullptr)
		m_pCurrState->Update(fElapsedTime);
}

//***********************************************************
// Render
//	- render the game objects
void CGame::Render( void )
{
	// Clear the screen (0 = black, 255 = white)
	m_pD3D->Clear( D3DCOLOR_XRGB( 0, 0, 0 ) );	// black

	// Start D3D rendering
	m_pD3D->DeviceBegin();
	m_pD3D->SpriteBegin();

	{
		if(m_pCurrState != nullptr)
			m_pCurrState->Render();
		else
		{
			Title->Draw( _T("ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz"), 10, 10,  1.0f, D3DCOLOR_XRGB(255, 255, 255));
			Menu->Draw(  _T("ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz"), 10, 600, 1.0f, D3DCOLOR_XRGB(255, 255, 255));
		}

		//if(vFonts[language] != nullptr)
		//	vFonts[language]->Draw( _T("This is our menu font!"), 10, 10, 1.0f, D3DCOLOR_XRGB(87, 0, 0));

		//// Render the Entity Manager
		//m_pEM->RenderAll();

		//m_pBF->Draw( _T("1\t2\t3\t4\nABCDEFabcdef\n7"), 42, 300, 2.5,
		//	D3DCOLOR_ARGB( 255, 127, 0, 0 ) );

		//TOSTRINGSTREAM worldPOS;
		//worldPOS << "Position: (" << (int)LevelState::GetInstance()->GetPlayer()->GetPosition().x << ", " <<(int)LevelState::GetInstance()->GetPlayer()->GetPosition().y << ")";
		//font->Draw( worldPOS.str().c_str(), 50, 50, 0.4f, 
		//	D3DCOLOR_ARGB( 255, 255, 255, 255 ) );
	}

	// End the D3D rendering
	m_pD3D->SpriteEnd();
	m_pD3D->DeviceEnd();

	// Present the backbuffer to the screen
	m_pD3D->Present();
}

void CGame::ChangeState( IGameState* pNewState )
{
	// Exit the existing state
	if( m_pCurrState != nullptr )
	{
		m_pCurrState->Exit();
		m_pPrevState = m_pCurrState;
	}

	// Store the new state
	m_pCurrState = pNewState;

	// Enter the new state
	if( m_pCurrState != nullptr )
		m_pCurrState->Enter();
}

void CGame::LoadStrings()
{

}

void CGame::Pause()
{
	Paused = !Paused;
}

void CGame::StartWrappers( 
	HWND hWnd, HINSTANCE hInstance,
	int nWidth, int nHeight,
	bool bWindowed )
{
	// Initialize the Wrappers
	//m_pD3D->Initialize( hWnd, m_nScreenWidth, m_nScreenHeight, m_bIsWindowed, true );
	m_pDI->Initialize( hWnd, hInstance, DI_KEYBOARD | DI_JOYSTICKS );
	//m_pTM->Initialize( m_pD3D->GetDirect3DDevice(), m_pD3D->GetSprite() );
	m_pXA->Initialize();
	//m_pAS->Initialize();
}

void CGame::CreateFonts()
{
	Title = new TitleFont;
	Title->Initialize( _T("Resource/Images/Fonts/Title_Font.png"), 46, 87, 11, 9, false, _T(' '), CGame::GetInstance()->English );

	Menu = new MenuFont;
	Menu->Initialize( _T("Resource/Images/Fonts/Menu_Font.png"), 61, 78, 16, 6, false, _T(' '), CGame::GetInstance()->English );
		//_T("Resource/Images/Fonts/Title_Font.xml"));

	/*Font* font2 = new MenuFont;
	font2->Initialize( _T("Resource/Images/Fonts/EorzeanFont.png"), 42, 42, 12, 8, false, _T(' '), CGame::GetInstance()->Eorzean );

	Font* font3 = new MenuFont;
	font3->Initialize( _T("Resource/Images/Fonts/OldEnglish.png"), 42, 42, 12, 19, false, _T(' '), CGame::GetInstance()->Swedish );*/

	//vFonts.push_back( font1 );
	//vFonts.push_back( font2 );
	//vFonts.push_back( font3 );
}

void CGame::SetWindowed(bool b)
{
	m_bIsWindowed = b;
	m_pD3D->Resize( res.width, res.height, m_bIsWindowed );
}

void CGame::HideCursor(bool b)
{
	hideCursor = b;
	ShowCursor(!hideCursor);
}